(function(){
/*
 * Author: Gerald <gera2ld@163.com>
 */
function changeOrder(n) {
	// 把数列n中数字的全排列按从小到大的顺序
	// 每执行一次changeOrder则切换到下一个排列并返回true
	// 直到没有下一个排列了则返回false
	var i,j,x;
	for(i=2;i>=0&&n[i]>=n[i+1];i--);
	if(i<0) return false;
	for(j=i+1;j<3&&n[i]<n[j+1];j++);x=n[i];n[i]=n[j];n[j]=x;
	for(j=++i+3;i<j/2;i++) {x=n[i];n[i]=n[j-i];n[j-i]=x;}
	return true;
}
function search(e) {
	e.preventDefault();
	function check(s) {
		// 用eval进行计算并检查结果
		// 考虑到除法会造成误差，通过比较答案与24差距小于.001来判断
		// PS:
		// 作者尝试过直接从数组中读取数字和运算符进行运算，而不是用eval来运行一个字符串算式，
		// 结果明显慢了很多，所以放弃了。这可能是javascript的特性导致的，没有多作研究……
		var r=(0,eval)(s)-24;
		if(r<.001&&r>-.001) res.push('<li>'+s+'=24</li>');
	}
	var operator_ids,res=[],i,n=[],s;
	// 检测输入的数字，并按升序排序
	for(i=0;i<4;i++)
		if((e=Number(num[i].value))&&e>0&&e<14) n.push(e);
		else {
			ans.innerHTML='<center style="color:red">输入错误！</center>';
			return;
		}
	n.sort();
	// 最外层循环使用changeOrder遍历四个数字的全排列
	do {
		// operator_ids表示三个运算符对应在operators中的id（0-3）
		operator_ids=[0,0,0];
		// 这层循环尝试所有的运算符（共4*4*4=64种可能）
		do {
			// 这里将对已填好数字和运算符的算式尝试用各种可能的运算顺序进行计算
			// 并在需要的时候加上括号
			// 共有A(3,3)=6种顺序，但是021和201是等价的，即下面的(2)
			// (1) ((a {op1} b) {op2} c) {op3} d
			s=n[0]+operators[operator_ids[0]]+n[1];if(operator_ids[0]<2&&operator_ids[1]>=2) s="("+s+")";
			s=s+operators[operator_ids[1]]+n[2];if(operator_ids[1]<2&&operator_ids[2]>=2) s="("+s+")";
			s=s+operators[operator_ids[2]]+n[3];
			check(s);
			// (2) (a {op1} b) {op2} (c {op3} d)
			s=n[0]+operators[operator_ids[0]]+n[1];if(operator_ids[0]<2&&operator_ids[1]>=2) s="("+s+")";
			i=n[2]+operators[operator_ids[2]]+n[3];if(operator_ids[1]>=2||operator_ids[1]<2&&operator_ids[2]<2) i="("+i+")";
			s=s+operators[operator_ids[1]]+i;
			check(s);
			// (3) (a {op1} (b {op2} c)) {op3} d
			s=n[1]+operators[operator_ids[1]]+n[2];if(operator_ids[0]>=2||operator_ids[0]<2&&operator_ids[1]<2) s="("+s+")";
			s=n[0]+operators[operator_ids[0]]+s;if(operator_ids[0]<2&&operator_ids[2]>=2) s="("+s+")";
			s=s+operators[operator_ids[2]]+n[3];
			check(s);
			// (4) a {op1} ((b {op2} c) {op3} d)
			s=n[1]+operators[operator_ids[1]]+n[2];if(operator_ids[1]<2&&operator_ids[2]>=2) s="("+s+")";
			s=s+operators[operator_ids[2]]+n[3];if(operator_ids[0]>=2||operator_ids[0]<2&&operator_ids[2]<2) s="("+s+")";
			s=n[0]+operators[operator_ids[0]]+s;
			check(s);
			// (5) a {op1} (b {op2} (c {op3} d))
			s=n[2]+operators[operator_ids[2]]+n[3];if(operator_ids[1]>=2||operator_ids[1]<2&&operator_ids[2]<2) s="("+s+")";
			s=n[1]+operators[operator_ids[1]]+s;if(operator_ids[0]>=2||operator_ids[0]<2&&operator_ids[1]<2) s="("+s+")";
			s=n[0]+operators[operator_ids[0]]+s;
			check(s);
			// 尝试下一种运算符组合
			operator_ids[0]++;
			if(operator_ids[0]==4) {operator_ids[0]=0;operator_ids[1]++;}
			if(operator_ids[1]==4) {operator_ids[1]=0;operator_ids[2]++;}
		} while(operator_ids[2]<4);
	} while(changeOrder(n));
	ans.innerHTML=res.length?res.join(''):'<center style="color:red">没有答案！</center>';
}
function init(){
	var i,s=['<form id=game>请输入四个数字(1-13)：'],
			g=document.getElementById('twenty-four-points');
	for(i=0;i<4;i++) s.push('<input type=text maxlength=2> ');
	s.push('<input type=submit value=找答案><input type=reset></form><ol id=ans></ol>');
	g.innerHTML=s.join('');ans=g.querySelector('#ans');
	g=g.querySelector('#game');num=g.querySelectorAll('input[type=text]');
	for(i=0;i<4;i++) {
		num[i].onmouseover=function(e){this.focus();};
		num[i].onfocus=function(e){this.select();};
	}
	g.onsubmit=search;
	g.onreset=function(e){ans.innerHTML='';};
}
var operators=['+','-','*','/'],ans,num;
init();
})();
